/*
Autor: Alexander Savochkin, 2010-2013
New BSD License
*/

#pragma once

#include <map>
#include <string>
#include <set>

#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
#include <boost/log/common.hpp>

#include "ClientInfo.h"
#include "Config.h"
#include "Exception.h"
#include "Channel.h"

#include "LogDefinitions.h"

using std::map;
using std::string;
using std::set;
using boost::optional;
using namespace boost::posix_time;

namespace SRCLF {

using Config::Configuration;
namespace ClientRequestParsing {
namespace AST {
	struct Command;
}
}
using  ClientRequestParsing::AST::Command;

	template<typename TItem, typename TConnectId = std::string>
	struct AccessInfo
	{
		TItem item;
		optional<ClientId> owner_id;
		TConnectId can_watch;
		TConnectId can_control;
		TConnectId can_admin;
	};

	/**
	@class Manager
	@brief This class "contains" channels. Also it proceses commands from clients, tracks time (and call channels when it is time to update regulation).
	*/	
	class Manager
	{
		boost::log::sources::severity_logger< severity_level > logger;

		map<string, AccessInfo<Channel*> > channels;
		map<string, ClientId> captured_channel;
		ClientId client_id_sequence;
		map<ClientId, ClientInfo> client_id_2_info;
		set<string> registered_connections;
		
		///Timer to track regulation updates in channels		
		boost::asio::deadline_timer timer;
	public:
		Manager(void);
		~Manager(void);

		void processCommand(ClientId id, const string& str_cmd, string& response);
		void processCommand(ClientId id, const Command& command, string& response);
		void doControlOnChannels();

		bool canControlChannel(const string& channel_name, const ClientInfo* client_info) const;
		bool canAdminChannel(const string& channel_name, const ClientInfo* client_info) const;

		bool isCapturedControl(const string& channel_name, ClientId client_id) const;
		bool captureControl(const string& channel_name, const ClientInfo* client_info);

		void releaseControl(const string& channel_name);

		Channel* getChannelByName(const string& channel_name) const;

		void init(Configuration& config);

		//
		bool checkControlOnChannel(const string& channel_name, const ClientInfo* client_info, string& result) const;

		//
		bool checkAdminOnChannel(const string& channel_name, const ClientInfo* client_info, string& result) const;

		void notifyClientDisconnected(ClientId client_id);
		void notifyClientConnected( const ClientInfo& client_info );

		ClientId getNextClientId() { return client_id_sequence++; }

		///Gets the nearest channel update time in future
		ptime nextRegulateMoment() const;

		ClientId newClientId() { return client_id_sequence++; }

		const set<string>& getRegistredConnections() 
		{
			return registered_connections;
		}

	private:
		void onTimerAction();
		
		IOperatedInput* createInputBySectionName(const string& section_name, const Configuration& config);
		IOperatedOutput* createOutputBySectionName(const string& section_name, const Configuration& config);
		IRegulator* createRegulatorBySectionName(const string& section_name, const Configuration& config);
	};

} //namespace SRCLF

